package com.webinsky.web.resource;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.WebSession;

import com.webinsky.article.domain.MisArticle;
import com.webinsky.article.domain.MisArticleFilter;
import com.webinsky.article.domain.MisArticleFlowDescription;
import com.webinsky.article.domain.MisArticleMediaType;
import com.webinsky.article.domain.MisArticleOpSample;
import com.webinsky.article.domain.MisArticleRelate;
import com.webinsky.article.domain.MisArticleRelateVideo;
import com.webinsky.article.domain.MisArticleTag;
import com.webinsky.article.domain.MisArticleType;
import com.webinsky.article.domain.MisArticleVideo;
import com.webinsky.article.domain.MisArticles;
import com.webinsky.article.service.ArticleManagement;
import com.webinsky.article.service.RelationshipManagement;
import com.webinsky.common.proj.Lang;
import com.webinsky.common.utils.db.PageOrder;
import com.webinsky.common.utils.db.Pagnation;
import com.webinsky.domain.resource.Resource;
import com.webinsky.domain.user.Account;
import com.webinsky.folder.service.FolderManagement;
import com.webinsky.service.resource.ResManagement;
import com.webinsky.service.user.AuthorizationManagement;
import com.webinsky.web.data.ArticleCanModifyForm;
import com.webinsky.web.data.ArticleCreateForm;
import com.webinsky.web.data.ArticleExistForm;
import com.webinsky.web.data.ArticleFlow2OpSampleForm;
import com.webinsky.web.data.ArticleIdForm;
import com.webinsky.web.data.ArticleListFilterForm;
import com.webinsky.web.data.ArticleTagsForm;
import com.webinsky.web.data.ExportTemplate;
import com.webinsky.web.data.RelatedArticleForm;
import com.webinsky.web.data.Response;
import com.webinsky.web.utils.ExportToExcelUtil;
import com.webinsky.web.utils.WebSessionUtils;

import reactor.core.publisher.Mono;


@Component
public class ArticleResource {
	
	private static final Logger logger = LoggerFactory.getLogger(ArticleResource.class);
	
	@Autowired
	private ArticleManagement articleManagement;
	@Autowired
	private ResManagement resManagement;
	@Autowired
	private AuthorizationManagement authorizationManagement;
	@Autowired
	private FolderManagement folderManagement;
	@Autowired
	private RelationshipManagement relationshipManagement;
	
    @Value("${file.save.path}")
	private String fileSavePath;
	
	private void setRelateVideoName(MisArticle article){
		List<Integer> videoIds = new ArrayList<>();
		if ( article.getRelatedVideo() != null ){
			List<Integer> vIds = article.getRelatedVideo().stream().map(v -> v.getRelateVideoId()).collect(Collectors.toList());
			videoIds.addAll(vIds);
		}
		if ( !videoIds.isEmpty() ){
			List<Resource> videoRes = resManagement.getVideoResourceByIds(videoIds);
			if ( !videoRes.isEmpty() ){
				Map<String,Resource> videoResMap = videoRes.stream().collect(Collectors.toMap(Resource::getUid, Function.identity()));
				if ( article.getRelatedVideo() != null ){
					article.getRelatedVideo().forEach(v -> {
						String strId = String.valueOf(v.getRelateVideoId());
						if ( videoResMap.get(strId) != null ){
							v.setVideoName(videoResMap.get(strId).getName());
							v.setVideoFileName(videoResMap.get(strId).getFileName());
						}
					});
				}
			}
		}
	}
	
	private void setVideoName(MisArticle article){
		List<Integer> videoIds = new ArrayList<>();
		if ( article.getArticleVideo() != null ){
			List<Integer> vIds = article.getArticleVideo().stream().map(v -> v.getVideoId()).collect(Collectors.toList());
			videoIds.addAll(vIds);
		}
		if ( !videoIds.isEmpty() ){
			List<Resource> videoRes = resManagement.getVideoResourceByIds(videoIds);
			if ( !videoRes.isEmpty() ){
				Map<String,Resource> videoResMap = videoRes.stream().collect(Collectors.toMap(Resource::getUid, Function.identity()));
				if ( article.getArticleVideo() != null ){
					article.getArticleVideo().forEach(v -> {
						String strId = String.valueOf(v.getVideoId());
						if ( videoResMap.get(strId) != null ){
							v.setVideoUrl(videoResMap.get(strId).getName());
							v.setVideoName(videoResMap.get(strId).getName());
							v.setVideoFileName(videoResMap.get(strId).getFileName());
						}
					});
				}
			}
		}
	}

	private void setImageName(MisArticle article){
		List<Integer> imageIds = new ArrayList<>();
		if ( article.getArticleImage() != null ){
			List<Integer> vIds = article.getArticleImage().stream().map(v -> v.getImageId()).collect(Collectors.toList());
			imageIds.addAll(vIds);
		}
		if ( !imageIds.isEmpty() ){
			List<Resource> imageRes = resManagement.getImageResourceByIds(imageIds);
			if ( !imageRes.isEmpty() ){
				Map<String,Resource> imageResMap = imageRes.stream().collect(Collectors.toMap(Resource::getUid, Function.identity()));
				if ( article.getArticleImage() != null ){
					article.getArticleImage().forEach(v -> {
						String strId = String.valueOf(v.getImageId());
						if ( imageResMap.get(strId) != null ){
							v.setImageUrl(imageResMap.get(strId).getName());
							v.setImageName(imageResMap.get(strId).getName());
							v.setImageFileName(imageResMap.get(strId).getFileName());
						}
					});
				}
			}
		}
	}
	
	private void setVideosName(MisArticles misArticles){
		List<Integer> videoIds = new ArrayList<>();
		if ( misArticles.getArticles() != null ){
			misArticles.getArticles().forEach(e -> {
				if ( e.getArticleVideo() != null ){
					List<Integer> vIds = e.getArticleVideo().stream().map(v -> v.getVideoId()).collect(Collectors.toList());
					videoIds.addAll(vIds);
				}
			});
			if ( !videoIds.isEmpty() ){
				List<Resource> videoRes = resManagement.getVideoResourceByIds(videoIds);
				if ( !videoRes.isEmpty() ){
					Map<String,Resource> videoResMap = videoRes.stream().collect(Collectors.toMap(Resource::getUid, Function.identity()));
					misArticles.getArticles().forEach(e -> {
						if ( e.getArticleVideo() != null ){
							e.getArticleVideo().forEach(v -> {
								String strId = String.valueOf(v.getVideoId());
								if ( videoResMap.get(strId) != null ){
									v.setVideoUrl(videoResMap.get(strId).getName());
								}
							});
						}
					});
				}
			}
		}
	}
	
	
	private void setRelateVideosName(MisArticles misArticles){
		List<Integer> videoIds = new ArrayList<>();
		if ( misArticles.getArticles() != null ){
			misArticles.getArticles().forEach(e -> {
				if ( e.getRelatedVideo() != null ){
					List<Integer> vIds = e.getRelatedVideo().stream().map(v -> v.getRelateVideoId()).collect(Collectors.toList());
					videoIds.addAll(vIds);
				}
			});
			if ( !videoIds.isEmpty() ){
				List<Resource> videoRes = resManagement.getVideoResourceByIds(videoIds);
				if ( !videoRes.isEmpty() ){
					Map<String,Resource> videoResMap = videoRes.stream().collect(Collectors.toMap(Resource::getUid, Function.identity()));
					misArticles.getArticles().forEach(e -> {
						if ( e.getRelatedVideo() != null ){
							e.getRelatedVideo().forEach(v -> {
								String strId = String.valueOf(v.getRelateVideoId());
								if ( videoResMap.get(strId) != null ){
									v.setVideoName(videoResMap.get(strId).getName());
								}
							});
						}
					});
				}
			}
		} 
	}
	
	/**
	 * 下载Excel
	 * @param request
	 * @return
	 */
	public Mono<ServerResponse> exportExcel(ServerRequest request){
		return request.bodyToMono(ArticleListFilterForm.class).flatMap(form -> {
			logger.info("{}exportExcel filter = " + form);
			MisArticleFilter filter = new MisArticleFilter();
			filter.setArticleNo(form.articleNo);
			filter.setUpdator(form.userName);
			filter.setTitle(form.title);
			filter.setSiteId(Integer.valueOf(form.siteId));
			filter.setLang(Lang.parse(form.lang));
			Pagnation pagnation = new Pagnation();
			pagnation.setPageSize(form.pageSize);
			pagnation.setPageStart(form.pageStart);
			// 排序
			if ( form.orders != null && form.orders.orders != null ){
				form.orders.orders.forEach(o -> {
					PageOrder resOrder = new PageOrder();
					resOrder.setFieldName(o.field);
					resOrder.setIsAscOrDes(o.ascOrDes);
					pagnation.getOrders().add(resOrder);
				});
			}
			filter.setPagnation(pagnation);
			MisArticles misArticles = articleManagement.getExcelArticles(filter, form.detail);
			List<ExportTemplate> templates = new ArrayList<>();
			misArticles.getArticles().forEach(mis -> {
				ExportTemplate template = new ExportTemplate();
				setVideoName(mis);
				template.setArticleNo(mis.getArticleNo());
				template.setArticleTitle(mis.getTitle());
				template.setArticleAbstract(mis.getSummary());
				List<String> ops = new ArrayList<>();
				List<String> opsTitle = new ArrayList<>();
				List<String> workflow = new ArrayList<>();
				List<String> videoNames = new ArrayList<>();
				mis.getFlowDescription().forEach(flowOps -> {
					if ( flowOps.getOpSamples() != null && flowOps.getOpSamples().size() > 0 ){
						for ( int i = 0; i < flowOps.getOpSamples().size(); i ++ ){
							ops.add(flowOps.getOpSamples().get(i).getContent());
							opsTitle.add(flowOps.getOpSamples().get(i).getTips());
							if ( i == 0 ){
								workflow.add(flowOps.getTilte());
							} else {
								workflow.add("");
							}
						}
						
					} else {
						workflow.add(flowOps.getTilte());
					}
				});
				mis.getArticleVideo().forEach( video -> {
					videoNames.add(video.getVideoName());
				});
				template.setOps(ops);
				template.setOpsTips(opsTitle);
				template.setVideoNames(videoNames);
				template.setWorkflow(workflow);
				templates.add(template);
			});
			// export excel
			if ( misArticles.getTotalSize() > 0 ){
				//表头字段
				String prefix = form.siteId + "_" + form.lang + "_Article_";
	            String fileName =  ExportToExcelUtil.export(prefix, templates, fileSavePath);
	            return ServerResponse.ok().syncBody(Response.create(fileName, Response.STATUS_OK, ""));
			}
			return ServerResponse.ok().syncBody(Response.create("", Response.STATUS_NOTFOUND_ERROR, ""));
		});
	}
	
	/**
	 * @param request
	 * @return
	 */
	public Mono<ServerResponse> getArticleList(ServerRequest request){
		return request.bodyToMono(ArticleListFilterForm.class).flatMap(form -> {
			// 查询条件添加了canModify
			// 需要返回视频的文件名称和视频名称
			logger.info("[getArticleList] filter = " + form);
			MisArticleFilter filter = new MisArticleFilter();
			filter.setArticleNo(form.articleNo);
			if ( form.canModify != null ){
				filter.setCanModify(form.canModify);
			}
			filter.setUpdator(form.userName);
			filter.setTitle(form.title);
			filter.setSiteId(Integer.valueOf(form.siteId));
			filter.setLang(Lang.parse(form.lang));
			Pagnation pagnation = new Pagnation();
			pagnation.setPageSize(form.pageSize);
			pagnation.setPageStart(form.pageStart);
			// 排序
			if ( form.orders != null && form.orders.orders != null ){
				form.orders.orders.forEach(o -> {
					PageOrder resOrder = new PageOrder();
					resOrder.setFieldName(o.field);
					resOrder.setIsAscOrDes(o.ascOrDes);
					pagnation.getOrders().add(resOrder);
				});
			}
			filter.setPagnation(pagnation);
			// MisArticle里面 新增 canModify 字段
			MisArticles misArticles = articleManagement.getArticles(filter, form.detail);
			setRelateVideosName(misArticles);
			setVideosName(misArticles);
			return ServerResponse.ok().syncBody(Response.create(misArticles, Response.STATUS_OK, ""));
		});
	}

	/**
	 * @param request
	 * @return
	 */
	public Mono<ServerResponse> setArticleCanModify(ServerRequest request){
		return request.bodyToMono(ArticleCanModifyForm.class).flatMap(form -> {
			// 设置文章是否可编辑
			if ( form.articleIds != null && form.canModify >= 0 ){
				List<Integer> ids = form.articleIds;
				articleManagement.batchfixCanModify(ids, form.canModify);
			}
			return ServerResponse.ok().syncBody(Response.create("", Response.STATUS_OK, ""));
		});
	}

	/**
	 * @param request
	 * @return
	 */
	public Mono<ServerResponse> getArticle(ServerRequest request){
		return request.bodyToMono(ArticleIdForm.class).flatMap(form -> {
			// 需要返回视频的文件名称和视频名称
			MisArticle misArticle = articleManagement.getArticle(form.id, form.detail);
			if ( misArticle != null ){
				Account account = authorizationManagement.getByUserId(misArticle.getUserId());
				misArticle.setCreator(account.getLoginName());
				setRelateVideoName(misArticle);
				setVideoName(misArticle);
				setImageName(misArticle);
				return ServerResponse.ok().syncBody(Response.create(misArticle, Response.STATUS_OK, ""));
			}
			return ServerResponse.status(HttpStatus.NOT_FOUND).syncBody(Response.create("", Response.STATUS_NOTFOUND_ERROR, "文章没有找到"));
		});
	}
	/**
	 * @param request
	 * @return
	 */
	public Mono<ServerResponse> createOrUpdate(ServerRequest request){
		return request.session().zipWith(request.bodyToMono(ArticleCreateForm.class)).flatMap(data -> {
			ArticleCreateForm form = data.getT2();
			WebSession session = data.getT1();
			if ( form.siteId != null &&
					form.lang != null && 
						form.articleNo != null && 
							form.title != null &&
								form.fileName != null ){
				Lang lang = Lang.parse(form.lang);
				MisArticle article = new MisArticle();
				article.setId(form.id);
				article.setSiteId(Integer.valueOf(form.siteId));
				article.setLang(lang);
				Account account = WebSessionUtils.getAccount(session);
				article.setUserId(Integer.valueOf(account.getUid()));
				article.setUpdateById(Integer.valueOf(account.getUid()));
				article.setUpdateBy(account.getLoginName());
				article.setArticleNo(form.articleNo);
				article.setFileName(form.fileName);
				article.setTitle(form.title);
				article.setSummary(form.summary);
				article.setRemark(form.remark);
				// 設置流程簡述
				if ( form.flow2OpSample != null ){
					List<MisArticleFlowDescription> flowDes = new ArrayList<>();
					int index = 1;
					for ( ArticleFlow2OpSampleForm a2o : form.flow2OpSample ){
						MisArticleFlowDescription mafd = new MisArticleFlowDescription();
						mafd.setId(a2o.flowId);
						mafd.setArticleId(form.id);
						mafd.setIndex(index);
						mafd.setLang(lang);
						mafd.setTilte(a2o.flow);
						if ( a2o.opSamples != null ){
							List<MisArticleOpSample> opSamples = new ArrayList<>();
							MisArticleOpSample misOpSample = new MisArticleOpSample();
							MisArticleFlowDescription description = new MisArticleFlowDescription();
							misOpSample.setId(a2o.opSampleId);
							misOpSample.setIndexId(a2o.flowId);
							misOpSample.setArticleId(form.id);
							misOpSample.setContent(a2o.opSamples);
							misOpSample.setDescription(description);
							misOpSample.setType(MisArticleMediaType.Text);
							misOpSample.setLang(lang);
							misOpSample.setTips(a2o.tips);
							misOpSample.setTipsColor(a2o.tipsColor);
							opSamples.add(misOpSample);
							mafd.setOpSamples(opSamples);
						}
						flowDes.add(mafd);
						index ++;
					}
					article.setFlowDescription(flowDes);
				}
				// 相關文章
				if ( form.relatedArticle != null ){
					List<MisArticleRelate> relatedArticle = new ArrayList<>();
					for ( RelatedArticleForm raId : form.relatedArticle ){
						MisArticleRelate mr = new MisArticleRelate();
						mr.setArticleId(form.id);
						mr.setRelateArticleId(raId.articleId);
						mr.setId(raId.id);
						mr.setIndex(raId.index);
						relatedArticle.add(mr);
					}
					if ( !relatedArticle.isEmpty() ){
						article.setRelatedArticle(relatedArticle);
					}
				}
				// 图片
				if ( form.articleImage != null && !form.articleImage.isEmpty() ){
					article.setArticleImage(form.articleImage);
				}
				// 视频
				if ( form.articleVideo != null && !form.articleVideo.isEmpty() ){
					article.setArticleVideo(form.articleVideo);
				}
				// 相關視頻
				if ( form.relatedVideo != null ){
					List<MisArticleRelateVideo> relatedVideo = new ArrayList<>();
					for ( MisArticleVideo rvideo : form.relatedVideo ){
						MisArticleRelateVideo misRelateVideo = new MisArticleRelateVideo();
						misRelateVideo.setIndex(rvideo.getIndex());
						misRelateVideo.setArticleId(form.id);
						misRelateVideo.setId(rvideo.getId());
						misRelateVideo.setRelateVideoId(rvideo.getVideoId());
						relatedVideo.add(misRelateVideo);
					}
					if ( !relatedVideo.isEmpty() ){
						article.setRelatedVideo(relatedVideo);
					}
				}
				// 标签
				if ( form.tags != null ){
					List<MisArticleTag> tags = new ArrayList<>();
					for ( ArticleTagsForm tagForm : form.tags ){
						if (tagForm.tags != null) {
							for ( int tagId : tagForm.tags ){
								MisArticleTag tag = new MisArticleTag();
								tag.setLang(lang);
								tag.setTagcatId(tagForm.tagcat);
								tag.setTagId(tagId);
								tag.setId(tagForm.id);
								tags.add(tag);
							}
						}
					}
					if ( !tags.isEmpty() ){
						article.setTags(tags);
					}
				}
				articleManagement.addArticle(article);
				return ServerResponse.ok().syncBody(Response.create(article.getId(), Response.STATUS_OK, ""));
			}
			return ServerResponse.badRequest().syncBody(Response.create("", Response.STATUS_INTERNAL_ERROR, "參數錯誤"));
		});
	}
	/**
	 * @param request
	 * @return
	 */
	public Mono<ServerResponse> deleteArticle(ServerRequest request){
		return request.bodyToMono(ArticleIdForm.class).flatMap(form -> {
			articleManagement.deleteArticle(form.id, MisArticleType.Article);
			// 分类里面对应的文章
			folderManagement.deleteArticleFromFolder(form.id);
			return ServerResponse.ok().syncBody(Response.create("", Response.STATUS_OK, ""));
		});
	}

	/**
	 * 判断文章是否已经存在
	 * @param request
	 * @return
	 */
	public Mono<ServerResponse> isExistArticle(ServerRequest request){
		return request.bodyToMono(ArticleExistForm.class).flatMap(form -> {
			// 添加文章时，当“自定义编号” ，“文件名” 或“标题” 已存在时，请提示。不允许重复添加或覆盖
			boolean exist = articleManagement.isExsit(Integer.valueOf(form.siteId), form.lang, form.articleNo, form.title, form.fileName);
			return ServerResponse.ok().syncBody(Response.create(exist ? 1 : 0, Response.STATUS_OK, ""));
		});
	}



}
